.TITLE POWER .IDENT /10.01/ ; ; Copyright (c) 1995 by Mentec, Inc., U.S.A. ; All rights reserved ; ; ; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED ; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ; D. N. CUTLER 1-OCT-73 ; ; MODIFIED FOR RSX-11M-PLUS V2.1 BY: ; ; H. HUANG ; H. BERNSTEIN ; B. S. MCCARTHY ; ; MODIFIED FOR RSX-11M-PLUS VERSION 3.0 BY: ; ; S. C. ADAMS ; J. W. BERZLE ; M. PETTENGILL ; B. S. MCCARTHY ; J. C. FRANZINI ; ; MODIFIED BY: ; ; J. W. BERZLE 20-MAY-86 10.00 ; ; JWB174 -- MODIFY POWER DOWN CALL TO IPDRV ; ; D. Carroll 18-Oct-1995 10.01 ; DC404 - Include PSECT statement to allow ICB pool to be ; fully extended during sysgen ; ; ; ; POWERFAIL RECOVERY ; ; MACRO LIBRARY CALLS ; .MCALL EPKDF$,HDRDF$,HWDDF$,PCBDF$,TCBDF$,BGCK$A EPKDF$ ;DEFINE ERROR PACKET OFFSETS HDRDF$ ;DEFINE TASK HEADER OFFSETS HWDDF$ ;DEFINE HARDWARE REGISTERS PCBDF$ ;DEFINE PARTITION CONTROL BLOCK OFFSETS TCBDF$ ;DEFINE TASK CONTROL BLOCK OFFSETS ; ; POWERFAIL VECTOR ; .ASECT .=24 PWVCT: .WORD PDOWN ; .WORD PR7 ; .PSECT .IIF DF,K$$DAS&I$$CBP, .PSECT EXEC1 ;DC404 ;DC404 ;+ ; **-PDOWN-POWERFAIL INTERRUPT (DOWN) ; ; THIS ROUTINE IS ENTERED AS A RESULT OF A POWER DOWN INTERRUPT. ALL ; VOLATILE MACHINE REGISTERS ARE SAVED, THE POWERFAIL VECTOR IS SWITCHED ; TO THE POWER UP ROUTINE, AND THE PROCESSOR IS HALTED TO AWAIT THE ; POWER UP INTERRUPT. ;- PDOWN: ;REF LABEL .IF DF M$$PRO ; ; IN THE MULTIPROCESSING CASE, THIS IS THE ONLY PLACE THE VECTOR ; AT 24 EVER POINTS. THIS IS BECAUSE ON POWER-UP, THE HARDWARE ; MUST USE THE VECTOR AT PHYSICAL 24, NOT KERNEL VIRTUAL 24 (BECAUSE ; THERE ISN'T ANY KERNEL MAPPING AT THAT TIME). ; ; DUE TO THIS, WE HAVE THREE CONDITIONS WHICH CAN BRING US THRU ; THIS VECTOR. ; ; 1. POWERFAIL (POWER GOING DOWN) -- WE CAN DETERMINE THIS FROM THE ; FACT THAT MAPPING IS ENABLED (WHICH IT NEVER IS OTHERWISE). ; ; 2. POWER RETURNS (AFTER A POWERFAIL) -- WE CAN DETERMINE THIS FROM ; THE FACT THAT MAPPING IS NOT ENABLED, AND THE LOW MEMORY MAPPING ; FOR US IS SET UP IN THE $PWKA0 VECTOR (ONE WORD PER CPU). ; ; 3. POWER RETURNS (BUT WE NEVER POWERFAILED). THIS IS BECAUSE SOME ; UNCLEVER PERSON TURNED THE KEY ON (OR OTHERWISE BROUGHT BACK ; THE POWER) AND DIDN'T HAVE THE HALT KEY DOWN. IF THEY HAVE THE ; NEAT 11/70 REMOTE DIAGNOSTIC CONSOL, THEY CAN BE PARTIALLY EXCUSED, ; SINCE THEY HAVE NO ACTUAL HALT KEY (ALTHO THEY CAN USE THE LITTLE ; SLIDE SWITCH, WHICH MIGHT SURVIVE 100 OPERATIONS WITHOUT FAILURE). ; IN THIS CASE WE WILL HALT THE MACHINE, AND THEY WILL NEVER KNOW ; WHAT WE DID FOR THEM. SIGH. ; CACHE$ BYPASS ;;;MAKE SURE WE HAVE THE "REAL THING" BIT #1,SR0 ;;;ARE WE COMING UP OR GOING DOWN? BNE PDOWN1 ;;;IF NE WE'RE ON THE WAY DOWN ; ; NOW -- EITHER POWER UP OR SPURIOUS ; MOV $PWCSR,R0 ;;;GET IIST CSR ADDRESS MOV (R0),R2 ;;;GET IIST REGISTER VALUE SWAB R2 ;;;PUT CPU ID IN LOW BYTE BIC #177774,R2 ;;;MAKE IT ONLY TWO BITS BIG ASL R2 ;;;AND WORD INDEX ; ; DID WE GO DOWN??? ; MOV $PWKA0(R2),R1 ;;;GET KINAR0 VALUE FROM BEFORE BNE 10$ ;;;IF NE THERE IS ONE, WE DID PWRFAIL ; ; SOME CLEVER FELLOW POWERED UP THE CPU WITH THE HALT KEY UNHALTED. ; WE WILL HALT AND HE WILL PROBABLY NEVER KNOW WE DIDN'T CRASH THE ; POSSIBLE MP SYSTEM UNDERNEATH HIM. TOO BAD IT'S A WASTE OF SPACE ; TO GIVE HIM A SNAPPY ERRORMESSAGE. ; 5$: HALT ;;;HERE WE ARE BR 5$ ;;;OH NO YOU DON'T 10$: CLR $PWKA0(R2) ;;;SHOW WE ARE MORE OR LESS UP NOW DEC R1 ;;;REMOVE BIAS OF ONE ; ; R0 = IIST CSR ADDRESS ; R1 = KINAR0 VALUE FOR THIS CPU ; R2 = CPU ID * 2 FOR TABLE INDEXES ; ; ; WE WILL NOW SET UP THE KERNEL MAPPING AND TURN ON 18 BIT ; MODE SO THIS CPU CAN ACCESS THE LOW MEMORY CONTEXT WITH ; WHICH IT IS SO WELL FAMILIAR. AS FAR AS THE REST OF THE ; POWERFAIL CODE IS CONCERNED, IT ALWAYS HAS ITS OWN LOW MEMORY. ; ; THIS MEANS THAT THE CODE THAT LOADS THE KERNEL I SPACE REGISTERS ; CANNOT LOAD JUNK AND THEN CORRECT IT -- IT MUST LOAD (OVERLOAD) ; VALID INFORMATION SO THIS CODE DOESN'T GO AWRY. ; CLR R3 ;;;START WITH KINAR0 MOV #KINAR0,R4 ;;;DITTO 20$: MOV #77406,KINDR0-KINAR0(R4) ;;;SET UP FOR 4K RW MOV R3,(R4)+ ;;;LOAD ADDRESS ADD #200,R3 ;;;MOVE ANOTHER 4K CMP #KINAR0+16,R4 ;;;ARE WE DONE BHIS 20$ ;;;IF HIS NO ; ; NOW CORRECT KINAR0 AND KINAR7 WITH THE REAL VALUES. ; MOV R1,@#KINAR0 ;;;PUT REAL OFFSET IN PAGE 0 MOV #177600,@#KINAR0+16 ;;;PUT I/O PAGE ADDRESS IN PAGE 7 BIS #PMODE,PS ;;;PUT USER INTO PREVIOUS PS INC SR0 ;;;TURN ON MAPPING AND AWAY WE GO JMP PUP ;;;GO TO "NORMAL" POWERUP CODE .ENDC PDOWN1: MOV SP,$PWSTK ;;;SAVE CURRENT STACK POINTER MOV #$PWSTK,SP ;;;SET ADDRESS OF REGISTER SAVE AREA MOV R5,-(SP) ;;;SAVE REGISTERS R5 THRU R0 MOV R4,-(SP) ;;; MOV R3,-(SP) ;;; MOV R2,-(SP) ;;; MOV R1,-(SP) ;;; MOV R0,-(SP) ;;; ; ; MULTIPROCESSOR POWERFAIL SUPPORT: ; ; EACH PROCESSOR THAT POWERFAILS SETS ITS BIT IN A WORD ; WHICH CONTAINS THE MASK OF PROCESSORS IN THEIR SAVE-RESTORE ; CODE. THEY ALSO INTERRUPT ALL OTHER ONLINE PROCESSORS TO ; TELL THEM TO STOP WHAT THEY ARE DOING AND WAIT UNTIL THE ; POWERFAILED PROCESSORS ARE BACK UP AGAIN. ; ; ; SET OUR BIT IN THE POWERFAILED CPU FLAG WORD ; .IF DF M$$PRO LOCK$ $PWRLK,SPIN BIS $CPBIT,$PWRMK ;;;SET OUR BIT IN THE POWERFAIL MASK ULOCK$ $PWRLK,SPIN MOV $URMST,R1 ;;;GET MASK OF ONLINE URMS BIC $CPMSK,R1 ;;;MAKE IT PROCESSORS ONLY BIC $CPBIT,R1 ;;;NOT OURSELVES EITHER BEQ 5$ ;;;IF EQ NOBODY UP BUT US MOV #MP.PWF,R2 ;;;SET FUNCTION CODE IN R2 CALL $IIFNX ;;;XMIT FUNCTION 5$: ;;;REFERENCE LABEL .ENDC BIT #FE.EXT,$FMASK ;;;IS THIS A 22-BIT SYSTEM? BEQ 21$ ;;;IF EQ NO BIT #HF.UBM,$HFMSK ;;;IS THERE A UNIBUS MAP? BEQ 21$ ;;;IF EQ NO MOV #UBMPR+<31.*4>,R0 ;;;POINT PAST LAST MAP REGISTER MOV #31.,R1 ;;;SET COUNT OF REGISTERS TO SAVE 20$: MOV -(R0),-(SP) ;;;SAVE HIGH 6 BITS OF ADDRESS MOV -(R0),-(SP) ;;;SAVE LOW 16 BITS OF ADDRESS SOB R1,20$ ;;;LOOP FOR ALL UMRS 21$: BIS #PMODE,PS ;;;MAKE SURE PREVIOUS MODE IS USER MFPI SP ;;;SAVE USER STACK POINTER .IF DF S$$LIB BIC #^CPSMODE&PMODE,PS ;;;SET PREVIOUS MODE TO SUPERVISOR MFPI SP ;;;SAVE SUPERVISOR STACK POINTER .ENDC MOV #KINAR0+16.,R0 ;;;POINT TO KERNEL INSTR ADDRESS REG 7+2 MOV #UINAR0+16.,R1 ;;;POINT TO USER I PAR 7 +2 MOV #UINDR0+16.,R2 ;;;POINT TO USER I PDR 7 +2 .IF DF U$$DAS MOV #UDSAR0+16.,R3 ;;;POINT TO USER DATA ADDRESS REG 7+2 MOV #UDSDR0+16.,R4 ;;;POINT TO USER DATA DESC. REG 7+2 .ENDC ; DF U$$DAS .IF DF K$$DAS MOV #KDSAR0+16.,R5 ;;;POINT TO KERNEL DATA ADDRESS REG 7+2 .ENDC 10$: MOV -(R1),-(SP) ;;;SAVE USER INSTR ADDR REG MOV -(R2),-(SP) ;;;SAVE USER DESCRIPTOR REGISTER .IF DF U$$DAS MOV -(R3),-(SP) ;;;SAVE USER DATA ADDRESS REGISTER MOV -(R4),-(SP) ;;;SAVE USER DATA DESC. REGISTER .ENDC ; DF U$$DAS MOV -(R0),-(SP) ;;;SAVE KERNEL INSTR ADDR REG .IF DF K$$DAS MOV -(R5),-(SP) ;;;SAVE KERNEL DATA ADDRESS REGISTER .ENDC CMP R0,#KINAR0 ;;;ANY MORE TO SAVE? BHI 10$ ;;;IF HI YES .IF DF S$$LIB MOV #SDSAR0+16.,R0 ;;;POINT TO SUPER DATA ADDRESS REG 7+2 MOV #SDSDR0+16.,R1 ;;;POINT TO SUPER DATA DESC. REG 7+2 MOV #SISAR0+16.,R2 ;;;POINT TO SUPER INST ADDRESS REG 7+2 MOV #SISDR0+16.,R3 ;;;POINT TO SUPER INST DESC. REG 7+2 200$: MOV -(R0),-(SP) ;;;SAVE SUPER DATA ADDRESS REGISTER MOV -(R1),-(SP) ;;;SAVE SUPER DATA DESC. REGISTER MOV -(R2),-(SP) ;;;SAVE SUPER INST ADDRESS REGISTER MOV -(R3),-(SP) ;;;SAVE SUPER INST DESC. REGISTER CMP R0,#SDSAR0 ;;;DONE YET? BHI 200$ ;;;IF HI NO .ENDC ; DF S$$LIB .IF DF F$$LPP TST $HFMSK ;;;FPP HARDWARE PRESENT? BMI 210$ ;;;IF MI NO STFPS -(SP) ;;;STORE FLOATING POINT STATUS SETD ;;;SET FLOATING DOUBLE MODE STD R0,-(SP) ;;;SAVE FLOATING POINT REGISTERS STD R1,-(SP) ;;; STD R2,-(SP) ;;; STD R3,-(SP) ;;; LDD R4,R0 ;;; STD R0,-(SP) ;;; LDD R5,R0 ;;; STD R0,-(SP) ;;; 210$: CLR -(SP) ;;;PUSH AN ADDRESS OF ZERO CMP @#244,#$FPPR7 ;;;IS THERE A PIRQ REGISTER TO SAVE? BEQ 30$ ;;;IF EQ NO, DO DUMMY SAVE OF LOCATION 0 MOV #PIRQ,(SP) ;;;SET FOR SAVE OF PIRQ 30$: MOV @(SP),-(SP) ;;;SAVE PIRQ REGISTER OR CONTENTS OF 0 .ENDC .IF NDF M$$PRO MOV #PUP,PWVCT ;;;SWITCH TO POWER UP ROUTINE .ENDC MOV SP,$POWSP ;;;SAVE SP FOR POWER UP .IF DF I$$P11&I$$PFS MOV $IPUCB,R0 ;;;GET IP UCB BEQ 40$ ;;;IF EQ, DRIVER POWERFAIL NOT SET MOV (R0),R0 ;;;GET IP DCB MOV D.DSP(R0),R1 ;;;GET IP DRIVER DISPATCH TABLE BEQ 40$ ;;;IF EQ, DRIVER NOT LOADED MOV D.PCB(R0),R0 ;;;GET DRIVER PCB BEQ 40$ ;;;IF EQ, FORGET IT! MOV P.REL(R0),KINAR5 ;;;MAP DRIVER IN I-SPACE .IF DF K$$DAS MOV P.REL(R0),KDSAR5 ;;;MAP DRIVER IN D-SPACE .ENDC ; DF K$$DAS MOV D.VINI-2(R1),-(SP) ;;;GET POWER-DOWN ENTRY POINT CALL @(SP)+ ;;;CALL DRIVER 40$: ;;;REFERENCE LABEL .ENDC ; DF I$$P11&I$$PFS ; ; AT THIS POINT, WE HAVE ALL BUT HALTED. WE WILL PLACE OUR KINAR0 LOW ; MEMORY MAPPING IN THE CELL IN CPA'S LOW MEMORY. THIS IS A FLAG TO ; THE POWERUP ROUTINE THAT WE HAVE ACTUALLY POWERFAILED. IF WE FAIL ; TO DO THIS, THE POWERUP ROUTINE WILL JUST HALT (SINCE IT CAN'T TELL ; THAT FACT FROM THE CASE WHERE SOMEONE POWERED UP THE MACHINE WITH ; THE HALT KEY UP.) ; .IF DF M$$PRO MOVB $PROC2,R1 ;;;GET OUR CPU OFFSET MOV @#KINAR0,R0 ;;;GET OUR LOW MEMORY OFFSET CLR @#KINAR0 ;;;START USING CPA'S LOW MEMORY .IF DF K$$DAS CLR @#KDSAR0 ;;;D-SPACE TOO, IF ANY .ENDC INC R0 ;;;BIAS BY ONE, SO NEVER ACTUALLY ZERO MOV R0,$PWKA0(R1) ;;;STORE OUR LOW MEMORY POINTER .ENDC HALT ;;;WAIT FOR SOME JUICE! ;+ ; **-PUP-POWERFAIL INTERRUPT (UP) ; ; THIS ROUTINE IS ENTERED AS A RESULT OF A POWER UP INTERRUPT. ALL VOLATILE ; MACHINE REGISTERS ARE RESTORED, A SCHEDULE REQUEST IS FORCED FOR THE ; NULL TASK, THE POWERFAIL INDICATOR IS INCREMENTED, AND AN RTI IS ; EXECUTED. AT THE APPROPRIATE TIME THE DISPATCHER WILL CALL THE POWER ; RECOVERY ROUTINE TO ACTUALLY PROCESS THE POWER FAILURE. ;- PUP: MOV $POWSP,SP ;;;RE-LOAD SP FROM POWERFAIL .IF DF F$$LPP MOV (SP)+,@(SP)+ ;;;CONDITIONALLY RESTORE PIRQ OR LOC. 0 TST $HFMSK ;;;FPP HARDWARE PRESENT? BMI 1$ ;;;IF MI NO LDFPS #200 ;;;SET FLOATING DOUBLE MODE, NO TRAPS LDD (SP)+,R0 ;;;RESTORE FLOATING POINT REGISTERS STD R0,R5 ;;; LDD (SP)+,R0 ;;; STD R0,R4 ;;; LDD (SP)+,R3 ;;; LDD (SP)+,R2 ;;; LDD (SP)+,R1 ;;; LDD (SP)+,R0 ;;; LDFPS (SP)+ ;;;RESTORE FLOATING POINT STATUS .ENDC 1$: BIS #PMODE,PS ;;;SET PREVIOUS MODE TO USER .IF DF S$$LIB MOV #SDSAR0,R3 ;;;POINT TO SUPER DATA ADDRESS REG 0 MOV #SDSDR0,R2 ;;;POINT TO SUPER DATA DESC. REG 0 MOV #SISAR0,R1 ;;;POINT TO SUPER INST ADDRESS REG 0 MOV #SISDR0,R0 ;;;POINT TO SUPER INST DESC. REG 0 5$: MOV (SP)+,(R0)+ ;;;RESTORE SUPER INST DESC. REGISTER MOV (SP)+,(R1)+ ;;;RESTORE SUPER INST ADDRESS REGISTER MOV (SP)+,(R2)+ ;;;RESTORE SUPER DATA DESC. REGISTER MOV (SP)+,(R3)+ ;;;RESTORE SUPER DATA ADDRESS REGISTER CMP R0,#SISDR0+16. ;;;DONE YET? BLO 5$ ;;;IF LO NO .ENDC ; DF S$$LIB MOV #KINAR0,R0 ;;;POINT TO KERNEL INSTR ADDR REG 0 MOV #UINAR0,R1 ;;;POINT TO USER I SPACE PAR 0 MOV #UINDR0,R2 ;;;POINT TO USER D SPACE PDR 0 .IF DF U$$DAS MOV #UDSDR0,R3 ;;;POINT TO USER DATA DESC. REGISTER 0 MOV #UDSAR0,R4 ;;;POINT TO USER DATA ADDRESS REGISTER 0 .ENDC .IF DF K$$DAS MOV #KDSAR0,R5 ;;;POINT TO KERNEL DATA ADDR REG 0 .ENDC 10$: ;;;REF LABEL .IF DF K$$DAS MOV #77406,KDSDR0-KDSAR0(R5) ;;;SET 4K RW ACCESS MOV (SP)+,(R5)+ ;;;RESTORE KERNEL DATA INSTR ADDR REG ; ; IN THE MULTIPROCESSING, I+D SPACE CASE, WE WOULD NORMALLY TRY TO ; LOAD 1600 INTO KINAR7 AND SET IT FOR 4K RO. THIS WIPES US OUT, ; SINCE WE ARE EXECUTING OUT OF THESE REGISTERS. WE WILL DETECT ; THIS FACT, AND WILL DO ANYTHING TO KISAR7. ; .IF DF M$$PRO CMP R0,#KINAR0+16 ;;;ARE WE JUST ABOUT TO WIPE THE I/O PAGE? BNE 15$ ;;;IF NE NO CMP (SP)+,(R0)+ ;;;BUMP STACK AND ADDRESS BR 20$ ;;;SKIP ACTUAL LOAD INSTRUCTIONS 15$: ;;;REFERENCE LABEL .ENDC MOV #77402,KINDR0-KINAR0(R0) ;;;SET 4K RO ACCESS .IFF MOV #77406,KINDR0-KINAR0(R0) ;;;SET 4K RW ACCESS .ENDC MOV (SP)+,(R0)+ ;;;RESTORE KERNEL INSTR ADDR REG 20$: ;;;REFERENCE LABEL .IF DF U$$DAS MOV (SP)+,(R3)+ ;;;RESTORE USER DATA DESC. REGISTER MOV (SP)+,(R4)+ ;;;RESTORE USER DATA ADDRESS REGISTER .ENDC ; DF U$$DAS MOV (SP)+,(R2)+ ;;;RESTORE USER INST DESC. REGISTER MOV (SP)+,(R1)+ ;;;RESTORE USER INST ADDRESS REGISTER CMP R0,#KINAR0+16. ;;;DONE YET? BLO 10$ ;;;IF LO NO .IF DF K$$DAS!M$$EXT!S$$LIB MOV #S3$BTS,SR3 ;;;SET UP SR3 .ENDC .IF DF M$$PRO .IF DF K$$DAS MOV #77402,@#KINAR0+16 .ENDC .IFF INC SR0 ;;;TURN ON MEMORY MANAGEMENT .ENDC .IF DF S$$LIB BIC #^CPSMODE&PMODE,PS ;;;SET PREVIOUS MODE TO SUPER MTPI SP ;;;RESTORE SUPERVISOR STACK POINTER BIS #PMODE,PS ;;;SET PREVIOUS MODE TO USER TSTB $SUPFL ;;;CURRENT TASK USE SUPER MODE ? BEQ 25$ ;;;IF EQ NO BIS #10,SR3 ;;;TURN ON CSM INSTRUCTION 25$: ;;;REFERENCE LABEL .ENDC MTPI SP ;;;RESTORE USER STACK POINTER BIT #FE.EXT,$FMASK ;;;IS THIS A 22-BIT SYSTEM? BEQ 35$ ;;;IF EQ NO BIT #HF.UBM,$HFMSK ;;;DOES THIS SYSTEM HAVE A UNIBUS MAP? BEQ 35$ ;;;IF EQ NO MOV #UBMPR,R0 ;;;POINT TO FIRST MAP REGISTER MOV #31.,R1 ;;;SET COUNT OF REGISTERS TO RESTORE 30$: MOV (SP)+,(R0)+ ;;;RESTORE LOW 16 BITS OF ADDRESS MOV (SP)+,(R0)+ ;;;RESTORE HIGH 6 BITS OF ADDRESS SOB R1,30$ ;;;LOOP FOR ALL UMRS 35$: ;;;REF LABEL ; ; SHOW OTHER PROCESSORS THAT WE ARE BACK ON THE AIR ; .IF DF M$$PRO LOCK$ $PWRLK,SPIN BIC $CPBIT,$PWRMK ;;;CLEAR OUT OUR BIT FROM THE MASK .IFTF INC $PWRFL ;;;SHOW POWERFAIL HAPPENED .IFT INCB $PWRFL+1 ;;;URM POWERFAIL TOO BIS @$CPURM,$PFURM ;;;FOR ALL OUR URM'S ; ; AT THIS POINT, WE WANT TO ASSURE OURSELVES THAT THIS CPU WILL, IN FACT, ; GO THROUGH DIRXT AT SOME POINT IN THE FUTURE. THIS REQUIRES A TWO ; PRONGED ATTACK -- FIRST WE SET $IIPND SO THAT IF WE RETURN FROM A CLOCK ; INTERRUPT TO A USER PROGRAM, THEN WE WILL GO THRU THE EXEC. SECOND, ; WE FIX UP THE IDLE LOOP TO LOOK AT $IIPND ON EACH LOOP AROUND. ; BIS $CPBIT,$IIPND ;;;TELL US LATER THAT WE HAVE WORK ULOCK$ $PWRLK,SPIN .ENDC ; IF THE SYSTEM HAS ANY MK11 BOXES ON IT, WE WILL RESTORE THEM NOW, ; SINCE THE RTI MAY GO BACK TO A LOADED DRIVER (OR TASK) IN ONE. .IF DF M$$K11 CALL $MKSET ;;;RESET MK11 MEMORY BOXES .ENDC ; DF M$$K11 MOV (SP)+,R0 ;;;RESTORE R0 THRU R5 MOV (SP)+,R1 ;;; MOV (SP)+,R2 ;;; MOV (SP)+,R3 ;;; MOV (SP)+,R4 ;;; MOV (SP)+,R5 ;;; MOV (SP),SP ;;;RESTORE STACK POINTER MOV #$ACTHD,@$RQSCH ;;;FORCE REDISPATCHING .IF NDF M$$PRO MOV #PDOWN,PWVCT ;;;SWITCH TO POWER DOWN ROUTINE ; AT THIS POINT WE WILL BYPASS THE CACHE. THIS PREVENTS GETTING STUCK ; IN $PWRMP, AND ALSO ASSURES THAT IF THE CODE INTERRUPTED BY POWERFAIL ; RUNS WITH CACHE BYPASSED, IT WILL BE AFTER THE POWERFAIL. (NOTE THAT ; THE SYSTEM WILL ALWAYS BE CACHE BYPASSED BETWEEN POWER RECOVERY AND ; THE FIRST ENTRY TO THE EXEC) .IFF CACHE$ BYPASS ;;;GET THE REAL THINGS .ENDC MOV $CKLDC,@$CKCNT ;;;RELOAD CLOCK COUNT REGISTER MOV #K$$IEN,@$CKCSR ;;;TURN CLOCK BACK ON RTI ;;; ;+ ; **-$POWER-POWER FAIL RECOVERY ; ; THIS ROUTINE WILL PERFORM POWERFAIL AND INITIALIZATION FOR ACTIVE ; TASKS AND DEVICES. ; ; INPUTS: ; ; $PWRFL=GENERAL POWERFAIL FLAG: ; 0 - DON'T INVOKE ACTIVE TASK POWERFAIL AST'S AND DON'T ; CALL DRIVERS WITHOUT KRBS. $PWRFL+1 MUST BE ; NON-ZERO OR WE WOULDN'T BE HERE. ; 1 - CALL ALL ACTIVE TASKS WITH POWERFAIL AST'S, AND ; ALL DRIVERS TOO. ; ; $PWRFL+1=DEVICE POWERFAIL FLAG: ; 0 - $PWRFL MUST HAVE BEEN SET OR WE WOULDN'T BE HERE. ; 1 - DO ONLY DEVICE POWERFAIL, AND CHECK $PFURM FOR THE ; UNIBUS RUN MASKS WHICH DEFINE THE RUNS TO PWRFAIL. ; ; $PFURM=MASK DEFINING THE RUNS FOR POWERFAIL IF $PWRFL+1<>0. ; OTHERWISE THIS SHOULD BE ZERO. ; ;- .ENABL LSB $POWER::TSTB $PWRFL ;IS IT GENERAL (FIRST) PWRFAIL? BEQ 16$ ;IF EQ NOT GENERAL POWERFAIL .IF DF K$$W11 CLR K$$W11+2 ;CLEAR CLOCK ERROR FLAGS MOV #1,K$$W11+6 ;ENERGIZE OUTPUT RELAY .ENDC ; ; EFFECT POWERFAIL AST'S FOR TASKS THAT ARE ACTIVE AND IN CORE ; MOV $ACTHD,R5 ;GET ADDRESS OF FIRST TCB 10$: MOV #AS.PFA,R4 ;GET CODE FOR POWER FAIL AST MOV T.ACTL(R5),-(SP) ;SAVE POINTER TO NEXT ACTIVE TASK BEQ 15$ ;IF EQ THERE IS NONE CALL $DASTT ;DECLARE POWERFAIL AST 15$: MOV (SP)+,R5 ;GET ADDRESS OF NEXT ACTIVE TASK BNE 10$ ;IF NE NO ; ; DO POWERFAIL RECOVERY FOR ALL ACTIVE DEVICES ; ; IF THE POWERFAIL IS FOR A CPU URM, THEN INITIALIZE THE CACHE AND ; MEMORY PARITY REGISTERS FOR THAT PROCESSOR. ; 16$: ;REFERENCE LABEL .IF DF M$$PRO BIT $CPBIT,$PFURM ;IS IT A POWERFAIL FOR THIS CPU? BEQ 22$ ;IF EQ NO -- JUST DO DEVICES .IFTF MOV #21$,-(SP) ;INLINE SUBROUTINE CALL .IFT BR 18$ ;SKIP IIST INITIALIZATION ON PWRFL .ENDC ;+ ; **-$CPNIT-INITIALIZE CPU AT POWERFAIL, STARTUP, ONLINE. ; ; THIS ROUTINE WILL PERFORM COMMON CPU INITIALIZATION FOR INITL, ; SAVE, AND LOWCR CPU STARTUP. ; ; INPUTS: ; ; NONE. ; ; OUTPUTS: ; ; INITIALIZATION PERFORMED. ; ; NO REGISTERS ARE PRESERVED. ;- $CPNIT:: ;REFERENCE LABEL .IF DF M$$PRO ; SET UP MK11 MEMORY BOXES, IN CASE WE NEED THEM .IF DF M$$K11 CALL $MKSET ;SET MK11 MEMORY BOXES BCS 17$ ;IF CS DIDN'T FIND THEM ALL .ENDC ; DF M$$K11 CALL $IINIT ;INITIALIZE THE IIST BIS $CPBIT,$URMST ;WE ARE ONLINE FOR SURE CALL $IINOT ;SEE IF WE CAN TALK TO OTHER CPUS 17$: MOV R2,$SCRET ;SET STATUS RETURN CALL $OLRNT ;SEND STATUS TO OLR .ENDC 18$: CALL $DRDSE ;ALWAYS DECLARE SIG. EVENT AT CPU PWRUP. .IF DF P$$RTY CALL $CLPAR ;CLEAR MEMORY PARITY CSR'S MOV $MPCSR+6,R0 ;GET ADDRESS OF 11/70 CACHE CSR REGISTER .IF DF P$$D70 MOV $MPCTL,(R0) ;SET UP 11/70 CACHE .IFF MOV #3,(R0) ;DISABLE TRAPS .ENDC .ENDC ; DF P$$RTY RETURN 21$: ;REF LABEL .IF DF P$$RTY MOV #177777,-(R0) ;CLEAR MEMORY ERROR REGISTER .ENDC ; DF P$$RTY .IF DF E$$LOG BIT #ES.DAT,$ERFLA ;ARE WE LOGGING DATA PACKETS? BEQ 22$ ;IF EQ NO MOV #E$CSYS+,R0 ;GET POWER FAIL ERROR CODE CLR R1 ;INDICATE NO DATA SUBPACKET MOV #SM.HDR,R2 ;ONLY LOG A HEADER SUBPACKET CALL $CREQU .ENDC ; DF E$$LOG ;+ ;**-DRVPF-LOCAL ENTRY FOR DRIVER ONLY POWER FAIL ;- DRVPF: ;CALLED FROM $DRVPF BELOW ; ; SCAN DEVICES FROM THE CTB SIDE (I.E. PHYSICAL) AND CHECK TO MAKE ; SURE THEY ARE ALL THERE. ; 22$: ;REFERENCE LABEL .IF DF M$$NET MOV $NETPF,R5 ;GET ADDRESS OF NETWORK POWERFAIL ;RECOVERY ROUTINE BEQ 225$ ;IF EQ THERE IS NONE CALL (R5) ;CALL POWER RECOVERY ROUTINE .ENDC ; DF M$$NET 225$: MOV #27$,-(SP) ;RETURN TO HERE AFTER $SGFIN CALL $SGFIN ;WE EXPECT TRAPS TO FOUR MOV #$CTLST,R3 ;GET ADDRESS OF FIRST ADDRESS OF CTBS 23$: MOV (R3),R3 ;GET ADDRESS OF NEXT CTB BEQ 35$ ;IF EQ NO MORE -- EXIT $SGFIN MOVB L.NUM(R3),R4 ;GET NUMBER OF KRBS MOV R4,R5 ;COPY NUMBER ASL R5 ; *2 ADD R3,R5 ; ADD #L.KRB,R5 ;POINTER TO JUST BEYOND LAST KRB ADDR 24$: DEC R4 ;ONE LESS TO GO BLT 23$ ;IF LT NO MORE MOV -(R5),R2 ;GET KRB ADDRESS BEQ 24$ ;THERE IS NO KRB ADDRESS IN LIST BIT #KS.OFL,K.STS(R2) ;IS IT OFFLINE? BNE 24$ ;IF NE YES -- DONT CHECK IT .IF DF M$$PRO BIT K.URM(R2),$PFURM ;SHOULD WE DO THIS ONE? BEQ 24$ ;IF EQ NO BIT K.URM(R2),@$CPURM ;IS IT ON THIS PROCESSOR? BEQ 24$ ;IF EQ NO .ENDC ; ; CALL DRIVER AT THE POWERFAIL-KRB ENTRY POINT ; MOV L.DCB(R3),R1 ;GET DCB ASSOCIATED WITH THIS CTB MOV CI.PWF(R1),R0 ;ASSUME IT WASN'T DCB BUT COMMON INT TBL BITB #LS.CIN,L.STS(R3) ;WAS IT COMMON INTERRUPT TABLE? BNE 25$ ;IF NE YES -- GO AND CALL DRIVER IMMED. ; ; R4 CONTAINS DCB ADDRESS. MAP AND CALL NORMAL DRIVER ; MOV D.PCB(R1),R0 ;GET PCB OF LOADED DRIVER MOV P.REL(R0),KINAR5 ;MAP DRIVER IN I-SPACE .IF DF K$$DAS MOV P.REL(R0),KDSAR5 ;MAP DRIVER IN D-SPACE .ENDC MOV D.DSP(R1),R1 ;GET DDT ADDRESS MOV D.VPWF(R1),R0 ;GET ADDRESS OF DRIVER POWERFAIL ENTRY ; ; IF POWERFAIL ADDRESS EXISTS, CALL DRIVER AFTER SAVING REGISTERS. ; 25$: TST R0 ;IS THERE A POWERFAIL ENTRY? BEQ 24$ ;IF EQ NO -- TRY NEXT KRB MOV R5,-(SP) ;SAVE POINTER TO NEXT KRB ADDRESS IN CTB MOV R4,-(SP) ;SAVE NUMBER OF KRB'S LEFT IN THIS CTB MOV R3,-(SP) ;SAVE CTB POINTER ; CALL DRIVER AT POWERFAIL ENTRY POINT WITH THE ARGUMENTS: ; ; C=1 TO SHOW CONTROLLER POWERFAIL (NOT UNIT POWERFAIL). ; R2=KRB ADDRESS. ; R3=CTB ADDRESS. ; ; ALL REGISTERS MAY BE USED. ; SEC ;SHOW KRB POWERFAIL, NOT UCB POWERFAIL CALL (R0) ;CALL DRIVER MOV (SP)+,R3 ;RESTORE CTB ADDRESS MOV (SP)+,R4 ;RESTORE NUMBER OF KRB'S LEFT IN THIS CTB MOV (SP)+,R5 ;RESTORE KRB ADDRESS BR 24$ ;GO TO NEXT KRB AND KEEP TRYING ; ; NOW SCAN DEVICES FROM THE DCB (I.E. LOGICAL) ORIENTATION AND CALL ; THE DRIVER FOR THE APPROPRIATE ONES. ; 27$: MOV #$SCDVT,-(SP) 30$: CALL @(SP)+ ;GET NEXT UCB ADDRESS BCC 40$ ;IF CC GOT ONE .IF DF M$$PRO BIC @$CPURM,$PFURM ;WE JUST DID POWERFAIL FOR OUR CPU .ENDC CLRB $PWRFL ;CPU POWERFAIL COMPLETE .IF DF M$$PRO TST $PFURM ;ANY URM'S LEFT TO PWRFAIL ON OTHER CPU? BNE 35$ ;IF NE YES -- EXIT NOW CLRB $PWRFL+1 ;CLEAR OUT URM POWERFAIL INDICATION .ENDC 35$: RETURN 40$: MOV #30$,-(SP) ;SET RETURN ADDRESS BITB #US.OFL,U.ST2(R5) ;DEVICE IN CONFIGURATION BNE 35$ ;IF NE DEVICE IS NOT IN CONFIG MOV S.KRB(R4),R2 ;GET KRB ADDRESS .IF DF M$$PRO BNE 43$ ;IF NE THERE IS A KRB ADDRESS TSTB $PWRFL ;IS THIS TOTAL PWRFAIL OR JUST DEVICES BEQ 35$ ;IF EQ NOT TOTAL -- TRY AGAIN BR 45$ ;GO DO THIS ONE .IFF BEQ 45$ ;IF EQ NO KRB ADDRESS .IFT 43$: BIT K.URM(R2),$PFURM ;SHOULD WE CHECK OUT THIS DEVICE? BEQ 431$ ;IF EQ NO BIT K.URM(R2),@$CPURM ;IS IT ON THIS PROCESSOR? BNE 44$ ;IF NE YES BR 35$ ;EQ - NO ; CHECK FOR A DUAL PORT, LOAD SHARE DEVICE WHERE ONLY ONE PORT'S URM, ; NAMELY THE ONE THAT IS NOT THE CURRENT OWNER (S.KRB) POWERFAILED 431$: MOV #S2.MAD!S2.LDS,R0 ;GET STATUS BITS BIC S.ST2(R4),R0 ;ARE ALL OF THE ABOVE SET BNE 35$ ;IF NE NO - NOT LOAD SHARING MOV S.KTB(R4),R0 ;ASSUME THIS IS PORT A BIT #KP.OFL,R0 ;IS PORT A ONLINE BEQ 35$ ;IF EQ NO, NO ONLINE PORT PWFLD CMP R0,R2 ;PORT A ? BNE 432$ ;IF NE NO - TAKE THIS ONE MOV S.KTB+2(R4),R0 ;POINT TO OTHER PORT BIT #KP.OFL,R0 ;IS IT ONLINE ? BEQ 35$ ;IF EQ NO, NO ONLINE PORT PWFLD 432$: MOV R0,R2 ;POINT TO OTHER KRB BIT K.URM(R2),$PFURM ;THAT PORT POWERFAIL ? BEQ 35$ ;IF EQ NO (THAT WAS A LOT OF WORK ; FOR NOTHING) BIT K.URM(R2),@$CPURM ;OTHER PORT ON THIS PROCESSOR BEQ 35$ ;IF EQ NO (DON'T WORRY, WE'LL ;CATCH IT LATER ON ANOTHER CPU) .ENDC 44$: BIT #KS.OFL,K.STS(R2) ;IS CONTROLLER OFFLINE? BEQ 45$ ;IF EQ NO TSTB U.STS(R5) ;IS UNIT ACTIVE? BPL 35$ ;IF PL NO ; ; THE CONTROLLER IS OFFLINE, AND THE UNIT IS ACTIVE. WE HAVE A ; PROBLEM. WE CANNOT CALL THE DRIVER AT THE CANCEL ENTRY SINCE ; THE DEVICE REGISTERS DO NOT EXIST. ; BGCK$A BF.ERR,BE.CSR,FATAL ;ACTIVE CONTROLLER DISAPPEARED AT PWRFL 45$: BITB #UC.PWF,U.CTL(R5) ;CALL DRIVER REGARDLESS OF ACTIVITY? BNE 50$ ;IF NE YES TSTB U.STS(R5) ;IS UNIT ACTIVE? BPL 35$ ;IF PL NO 50$: MOV D.DSP(R3),R2 ;GET ADDRESS OF DRIVER DISPATCH TABLE BEQ 35$ ;IF EQ DRIVER NOT LOADED ;+ ; **-$LDPWF-CALL DRIVER AT POWERFAIL ENTRY. ; ; THIS ROUTINE WILL UNCONDITIONALLY CALL THE DRIVER AT ITS POWERFAIL ; ENTRY FOR A SINGLE UNIT. ; ; INPUTS: ; ; R2=DDT ADDRESS. ; R3=DCB ADDRESS. ; R4=SCB ADDRESS. ; R5=UCB ADDRESS. ; ; OUTPUTS: ; ; NONE ; ; NO REGISTERS ARE PRESERVED! ;- $LDPWF::MOV KINAR5,-(SP) ;SAVE KERNEL INSTR ADDR REG 5 .IF DF K$$DAS MOV KDSAR5,-(SP) ;SAVE KERNEL DATA ADDR REG 5 .IFTF MOV D.PCB(R3),R3 ;GET DRIVER PCB ADDRESS MOV P.REL(R3),KINAR5 ;MAP THE DRIVER .IFT MOV P.REL(R3),KDSAR5 ;MAP DRIVER IN DATA SPACE .IFTF 55$: MOV S.KRB(R4),R3 ;GET KRB ADDRESS BEQ 60$ ;IF EQ NO KRB ADDRESS MOVB K.CON(R3),R3 ;GET CONTROLLER INDEX ; ; CALL DRIVER AT POWERFAIL ENTRY POINT WITH THE ARGUMENTS: ; ; R3=CONTROLLER INDEX. ; R4=ADDRESS OF THE STATUS CONTROL BLOCK. ; R5=ADDRESS OF THE UNIT CONTROL BLOCK. ; ; IF S.KRB=0 THEN R3 IS UNDEFINED. ; 60$: TST D.VPWF(R2) ;IS THERE AN ENTRY ? BEQ 70$ ;IF EQ NO CLC CALL @D.VPWF(R2) ;CALL DRIVER AT POWERFAIL ENTRYPOINT 70$: ;REFERENCE LABEL .IFT MOV (SP)+,KDSAR5 ;RESTORE KERNEL DATA ADDR REG 5 .ENDC MOV (SP)+,KINAR5 ;RESTORE KERNEL INSTR ADDR REG 5 RETURN ; .DSABL LSB .IF DF M$$PRO $PWRMP::CACHE$ BYPASS ;;;GET ACTUAL WORD IN MEMORY ; ; REMOVE OUR BIT FROM $STENB ; MOV $STENB,R0 ;;;GET CURRENT STATUS 5$: CACHE$ BYPASS ;;;KEEP FORCING BYPASS IN CASE OF PWR FAIL BIC $CPBIT,$STENB ;;;CLEAR OUT OUR BIT BIT $CPBIT,$STENB ;;;BREAK TIES BNE 5$ ;;;FIX ONE IN A MILLION RACE CONDITION MOV $CPBIT,R1 ;;;GET OUR CPU BIT COM R1 ;;;MAKE IT BIT CLEAR MASK BIC R1,R0 ;;;LEAVE ONLY OUR BIT IN R0 CALL $STTIC ;;;MAKE SURE THE SANITY TIMER IS OFF 10$: CACHE$ BYPASS ;;;KEEP FORCING BYPASS IN CASE OF PWR FAIL TST $PWRMK ;;;ANYONE IN THE POWERFAIL AREA BNE 10$ ;;;IF YES KEEP TRYING BIS R0,$STENB ;;;SET OUR BIT AGAIN CACHE$ RESTOR ;;;UNBYPASS THE CACHE RETURN .ENDC ;+ ;**-$MKSET-RESET MK11 CSR'S ON CPU ONLINE ; ; THIS ROUTINE IS CALLED TO RESTORE THE SETTING OF MK11 CSR'S (USING ; $MKCSR,$MKCS1,$MKCS2) AFTER POWER FAILURE AND RECOVERY, AND AT CPU ; ONLINE TIME TO BRING PARITY (NO PUN INTENDED) TO THE NEW PROCESSOR'S ; OUTLOOK ON MEMORY. ; ; INPUTS: ; ; NONE. ; ; OUTPUTS: ; ; MK11 MEMORY BOXES REMAPPED ; ; R0,R1 ARE DESTROYED ; R2 = STATUS (VALID ONLY IF $MKSET) ; C = 1 IF ANY ONLINE BOX (IN $MKCSR) IS NOT IN I/O PAGE ;- .IF DF M$$K11 ; NOTE: THE FOLLOWING CODE ASSUMES THAT WE ARE CALLED ON CPU ; ONLINE IN A SECTION PROTECTED BY $SGFIN (I.E. MPENT) ; AND THAT POWERFAIL DOES NOT CALL $SGFIN. THIS WAY, IF ; A CSR "DISAPPEARS" WHILE POWERED DOWN, THE SYSTEM WILL ; CRASH. IF IT DISSAPEARS BEFORE PROCESSOR ON-LINE (E.G. ; SWITCHES NOT SET CORRECTLY) THE ON-LINE TRANSITITION IS ; REJECTED. $MKSET::MOV #$MKCSR,R0 ;POINT TO FIRST CSR ADDRESS MOV #IE.ONP,R2 ;ASSUME CSR'S NOT PRESENT 10$: MOV (R0)+,R1 ;GET FIRST/NEXT CSR ADDRESS CMP #160000,R1 ;IS IT A CSR ADDRESS ? BHI 20$ ;IF HI NO, IT'S A DUMMY CLC ;ASSUME THAT THE CSR EXISTS MOV $MKCS1,(R1) ;STUFF CSR1 WITH CONTROL VALUE BCS 30$ ;IF CS DIDN'T EXIST MOV $MKCS2-$MKCSR-2(R0),2(R1) ;CRAM CSR2 WITH START ADDR 20$: CMP R0,#$MKCS2 ;REACHED THE END YET ? BLO 10$ ;IF LO NO, CONTINUE MOV #1,R2 ;SET SUCCESS (NOTE C-BIT MUST BE CLEAR ;FOR BLO TO HAVE DROPPED THROUGH) 30$: RETURN ;BACK TO CALLER .ENDC ; DF M$$K11 ;+ ;**-$DRVPF-CALL DRIVERS FOR POWERFAIL RECOVERY ; ; THIS ENTRY POINT IS PROVIDED SPECIFICALLY FOR USE BY AUTOCONFIGURE ; TO RECOVER THE SYSTEM. THE DEVICE DRIVERS ARE CALLED AT THEIR POWER ; FAIL ENTRY POINTS IN ORDER TO RE-ESTABLISH INTERRUPTS, ETC. ;- $DRVPF:: ;DRIVER POWERFAIL RECOVERY ENTRY MOV KISAR5,-(SP) ;SAVE APR 5 MAPPING (D OR I/D SPACE) .IF DF K$$DAS MOV KINAR5,-(SP) ;SAVE APR 5 MAPPING (I SPACE) .IFTF ; DF K$$DAS .IF DF M$$PRO BIS @$CPURM,$PFURM ;INDICATE THIS CPU'S URMS FAILED .ENDC ; DF M$$PRO CALL DRVPF ;CALL DRIVERS AT POWERFAIL .IFT ; DF K$$DAS MOV (SP)+,KINAR5 ;RESTORE APR 5 MAPPING (I SPACE) .ENDC ; DF K$$DAS MOV (SP)+,KISAR5 ;RESTORE APR 5 MAPPING (D OR I/D SPACE) RETURN ; .END